
package it.allerj.analysis;

import blobDetection.Blob;
import blobDetection.EdgeVertex;
import java.awt.Point;
import java.util.ArrayList;

public class DotMark implements Comparable<DotMark> {
    
    public Point.Float cropTop = new Point.Float(0,0);
    public Point.Float cropBottom = new Point.Float(0,0);
    
    private Point.Float center;
    private Point.Float upperLeftCorner;    
    private float image_w;
    private float image_h;
    private Float area;
    private Float perimeter;
    private float diameter;
    private ArrayList<EdgeVertex> vertexes = new ArrayList<EdgeVertex>();
    
    public DotMark() {
        this.center = new Point.Float();
        this.upperLeftCorner = new Point.Float();
        this.diameter = 0.0f;
    }
    
    public DotMark(Blob blob, int image_w, int image_h) {
        // store image dimensions
        this.image_w = image_w;
        this.image_h = image_h;
        
        // retrieve upper left corner            
        int ulx = Math.round(blob.xMin * image_w);
        int uly = Math.round(blob.yMin * image_h);
        this.upperLeftCorner = new Point.Float(ulx, uly);

        // retrieve blob center
        float x = blob.x * image_w;
        float y = blob.y * image_h;
        this.center = new Point.Float(x, y);

        // we suppose it's a quite perfect circle...
        float diam1 = blob.h * image_h;
        float diam2 = blob.w * image_w;
        this.diameter = (diam1 < diam2) ? diam1 : diam2;
        
        // store vertex of the polygon
        for (int m=0;m<blob.getEdgeNb();m++) {
            EdgeVertex eA = blob.getEdgeVertexA(m);
            if (eA !=null) {
                vertexes.add(eA);
            }
        }        
    }
    
    private void computeArea() {
        if (area != null) {
            return;
        }
        
        area = new Float(0);
        for (int i=0; i<vertexes.size()-1; ++i) {
            EdgeVertex vertex1 = vertexes.get(i);
            EdgeVertex vertex2 = vertexes.get(i+1);
            
            // remember! vertex are [0,1] normalized
            area += (vertex1.x * image_w) * (vertex2.y * image_h);
            area -= (vertex2.x * image_w) * (vertex1.y * image_h);
        }
        
        // area could be negative
        area = Math.abs(area / 2);
    }
    
    private void computePerimeter() {
        if (perimeter == null) {
            return;
        }
        
        perimeter = new Float(0);
        for (int i=0; i<vertexes.size()-1; ++i) {
            EdgeVertex vertex_a = vertexes.get(i);
            EdgeVertex vertex_b = vertexes.get(i+1);
            if ((vertex_a == null)||(vertex_b == null)) continue;
            
            float ex = (vertex_b.x*image_w - vertex_a.x*image_w);
            float ey = (vertex_b.y*image_h - vertex_a.y*image_h);
            
            perimeter += (float) Math.sqrt(Math.pow(ex, 2) + Math.pow(ey, 2));
        } 
    }
    
    public float getArea() {
        if (area == null) {
            computeArea();
        }
        
        return area;
    }
    
    public float getPerimeter() {
        if (perimeter == null) {
            computePerimeter();
        }
        
        return perimeter;
    }
            
    public Point.Float getCenter() {
        return center;
    }
    
    public float getDiameter() {
        return diameter;
    }
    
    public Point.Float getUpperLeftCorner() {
        return upperLeftCorner;
    }
   
    public ArrayList<EdgeVertex> getVertexes() {
        return vertexes;
    }
    
    public Point.Float deNormalize(Point.Float p) {
        return new Point.Float( p.x*image_w, p.y*image_h);
    }

    public Point.Float mapToWorld(Point.Float p) {
        return new Point.Float( p.x + cropTop.x, p.y + cropTop.y);
    }
    
    public Point.Float getCropTop() {
        return cropTop;
    }
    
    public Point.Float getCropBottom() {
        return cropBottom;
    }

    public int compareTo(DotMark dm) {
        int ret = 0;
        if (this.getArea() < dm.getArea()) {
            ret = -1;
        }
        else if (this.getArea() > dm.getArea()) {
            ret = 1;
        }
        
        return ret;
    }
}